<template>
    <div class="buildItem">
        <div class="back" v-for="item in list">
            <div class="item" @click="selectModel(item.file)">
                <img :src="getThumbnailPath(item.file)" alt="模型缩略图" class="thumbnail" @error="onImageError($event, item.file)">
            </div>
        </div>
    </div>
</template>
<script setup>
import {ref, reactive, onUnmounted, watch} from 'vue';
import {getObjectViews, createGsapAnimation, THREE} from 'three-editor-cores'
import {ElMessage} from 'element-plus'
import {defHttp} from '@/util/http/index';

const props = defineProps(['activeKey', 'emitEditor']);

// 用于跟踪加载失败的图片
const failedImages = reactive(new Set());
// 当前选中的模型信息
const selectedModel = ref(null);
// 预览模型引用
let previewModel = null;
// 鼠标移动处理函数
let mouseMoveHandler = null;
// 鼠标点击处理函数
let mouseClickHandler = null;
// 鼠标右键处理函数
let handleRightClick = null;

// 获取缩略图路径，使用与模型文件同名的jpg图片
const getThumbnailPath = (fileName) => {
    // 提取文件名（不包含扩展名）
    const baseName = fileName.substring(0, fileName.lastIndexOf('.'));
    // 根据vite.config.ts中的base配置，需要包含'/3d-editor'基础路径
    return `/3d-editor/files/${props.activeKey}/${baseName}.jpg`;
}

// 处理图片加载失败的事件
const onImageError = (event, fileName) => {
    failedImages.add(fileName);
}

const list = ref([]);

// 加载模型列表的函数
function loadModelList() {
    defHttp.get({ url: '3d-editor/files/' + props.activeKey + '/index.json' }, { isTransformResponse: false }).then((res) => {
        list.value = res
    });
}

// 初始加载
loadModelList();

// 监听activeKey变化，重新加载对应的模型列表
watch(() => props.activeKey, () => {
    // 清除之前的选中状态
    clearSelectedModel();
    // 加载新的模型列表
    loadModelList();
});

// 选择模型
function selectModel(fileName) {
    const type = fileName.split('.').pop().toUpperCase()
    if (!type || !['FBX', 'GLB', 'GLTF', 'OBJ'].includes(type)) {
        return
    }
    // 清除之前的选中状态
    clearSelectedModel();
    // 设置当前选中的模型
    selectedModel.value = {
        fileName: fileName,
        type: type === 'GLB' ? 'GLTF' : type,
        url: '3d-editor/files/' + props.activeKey + '/' + fileName
    };
    // 预加载模型用于预览
    const rootInfo = {
        url: selectedModel.value.url,
        type: selectedModel.value.type,
        indexDBNameUrl: ''
    };
    props.emitEditor.loading = true;
    setTimeout(() => {
        if (props.emitEditor.loading) {
            props.emitEditor.loading = false;
            ElMessage.error('网络较差,加载比较缓慢');
        }
    }, 8000);
    const {loaderService} = props.emitEditor.threeEditor.modelCore.insertModel(rootInfo);
    loaderService.complete = m => {
        props.emitEditor.loading = false;
        previewModel = m;
        // 初始时隐藏模型
        previewModel.visible = false;
        // 添加鼠标事件处理
        setupMouseEvents();
        ElMessage.success('请将鼠标移动到3D视图中，点击放置模型');
    };
}

// 设置鼠标事件
function setupMouseEvents() {
    const {camera, DOM, scene} = props.emitEditor.threeEditor;
    // 鼠标移动处理
    mouseMoveHandler = (event) => {
        if (!previewModel || !selectedModel.value) return;
        // 检查鼠标是否在3D视图内
        if (DOM.contains(event.target)) {
            previewModel.visible = true;
            // 计算鼠标在场景中的位置
            const mouse = new THREE.Vector2();
            const rect = DOM.getBoundingClientRect();
            mouse.x = ((event.clientX - rect.left) / DOM.clientWidth) * 2 - 1;
            mouse.y = -((event.clientY - rect.top) / DOM.clientHeight) * 2 + 1;

            const raycaster = new THREE.Raycaster();
            raycaster.setFromCamera(mouse, camera);
            // 创建y=0的平面用于检测交点，确保只计算平面位置
            const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
            const intersectPoint = new THREE.Vector3();
            // 计算射线与平面的交点，只关注x和z轴位置
            if (raycaster.ray.intersectPlane(plane, intersectPoint)) {
                // 只更新x和z坐标，保持y坐标为0
                previewModel.position.x = intersectPoint.x;
                previewModel.position.z = intersectPoint.z;
                // 确保y坐标始终为0，只关注平面位置
                previewModel.position.y = 0;
            } else {
                // 备用方案：使用相机前方一定距离的点
                const targetPosition = new THREE.Vector3();
                camera.getWorldDirection(targetPosition);
                targetPosition.multiplyScalar(5);
                targetPosition.add(camera.position);
                // 只使用x和z坐标，y坐标固定为0
                previewModel.position.x = targetPosition.x;
                previewModel.position.z = targetPosition.z;
                previewModel.position.y = 0;
            }
        } else {
            previewModel.visible = false;
        }
    };

    // 鼠标点击处理 - 放置模型
    mouseClickHandler = (event) => {
        if (!previewModel || !selectedModel.value || !DOM.contains(event.target)) return;

        // 计算放置位置
        const mouse = new THREE.Vector2();
        const rect = DOM.getBoundingClientRect();
        mouse.x = ((event.clientX - rect.left) / DOM.clientWidth) * 2 - 1;
        mouse.y = -((event.clientY - rect.top) / DOM.clientHeight) * 2 + 1;

        const raycaster = new THREE.Raycaster();
        raycaster.setFromCamera(mouse, camera);

        // 创建y=0的平面，只关注平面位置
        const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
        const intersectPoint = new THREE.Vector3();
        // 计算射线与平面的交点
        const position = new THREE.Vector3();
        if (raycaster.ray.intersectPlane(plane, intersectPoint)) {
            // 只使用x和z坐标，y坐标固定为0
            position.x = intersectPoint.x;
            position.z = intersectPoint.z;
            position.y = 0;
        } else {
            // 备用方案：使用相机前方一定距离的点
            const targetPosition = new THREE.Vector3();
            camera.getWorldDirection(targetPosition);
            targetPosition.multiplyScalar(5);
            targetPosition.add(camera.position);
            // 只使用x和z坐标，y坐标固定为0
            position.x = targetPosition.x;
            position.z = targetPosition.z;
            position.y = 0;
        }
        // 创建最终的模型实例
        createFinalModel(position);
    };
    // 设置鼠标右键点击处理函数
    handleRightClick = function(event) {
        if (!previewModel || !selectedModel.value) return;
        // 阻止默认的右键菜单显示
        event.preventDefault();
        // 取消选择模型
        clearSelectedModel();
        ElMessage.info('已取消模型添加');
    };
    // 添加事件监听器
    document.addEventListener('mousemove', mouseMoveHandler);
    document.addEventListener('click', mouseClickHandler);
    // 添加右键点击取消功能
    document.addEventListener('contextmenu', handleRightClick);
}

// 创建最终的模型实例
function createFinalModel(position) {
    if (!selectedModel.value) return;
    const rootInfo = {
        url: selectedModel.value.url,
        type: selectedModel.value.type,
        indexDBNameUrl: ''
    };
    const {loaderService} = props.emitEditor.threeEditor.modelCore.insertModel(rootInfo);
    loaderService.complete = m => {
        // 设置模型位置
        m.position.copy(position);
        // 检查是否是机柜模型
        const isCabinetModel = props.activeKey === 'cabinet';
        if (isCabinetModel) {
            // 机柜模型不移动相机聚焦
            setTimeout(() => props.emitEditor.threeEditor.setOutlinePass([]), 1000);
        } else {
            // 非机柜模型保持原有相机聚焦行为
            const {maxView, target} = getObjectViews(m);
            Promise.all([
                createGsapAnimation(props.emitEditor.threeEditor.camera.position, maxView),
                createGsapAnimation(props.emitEditor.threeEditor.controls.target, target)
            ]).then(() => {
                props.emitEditor.threeEditor.controls.target.copy(target);
                setTimeout(() => props.emitEditor.threeEditor.setOutlinePass([]), 1000);
            });
        }
    };
    // 清除选中状态和预览模型
    clearSelectedModel();
}

// 清除选中的模型和事件监听
function clearSelectedModel() {
    if (previewModel && previewModel.parent) {
        previewModel.parent.remove(previewModel);
        previewModel = null;
    }
    selectedModel.value = null;
    if (mouseMoveHandler) {
        document.removeEventListener('mousemove', mouseMoveHandler);
        mouseMoveHandler = null;
    }
    if (mouseClickHandler) {
        document.removeEventListener('click', mouseClickHandler);
        mouseClickHandler = null;
    }
    // 移除右键点击事件监听器
    if (handleRightClick) {
        document.removeEventListener('contextmenu', handleRightClick);
        handleRightClick = null;
    }
}
// 组件卸载时清理
onUnmounted(() => {
    clearSelectedModel();
});
</script>
<style lang="less" scoped>
.buildItem {
    padding: 4px;
    box-sizing: border-box;
    display: grid;
    grid-template-rows: repeat(auto-fit, 48px);
    grid-template-columns: repeat(3, 1fr);
    grid-row-gap: 15px;
    overflow: scroll;
    height: 100%;
    justify-items: center;
    width: calc(100% - 60px);
    .back {
        height: 55px;
        width: 50px;
        border-radius: 6px;
        border: 1px solid #676768;
        display: flex;
        box-sizing: border-box;
        margin: 4px 0;
        padding: 2px;
    }
    .item {
        border: 1px solid #3d3d3d;
        border-radius: 3px;
        height: 100%;
        width: 47px;
        display: flex;
        justify-content: center;
        align-items: center;
        box-sizing: border-box;
    }

    .thumbnail {
        width: 100%;
        height: 100%;
        object-fit: contain;
        cursor: pointer;
        box-sizing: border-box;
    }
}
</style>
